# encoding: UTF-8

"""
CTA模块相关的GUI控制组件
"""

from base.strategy_engine import StrategyTestEngine
from ui.uiBasicWidget import QtCore, QtWidgets
from engine.event_engine import *
from ui.wStrategyRunningMonitor import Ui_StrategyRunningMonitor
from const_struct.db_const import *


class StrategyRunningMonitor(QtWidgets.QGroupBox, Ui_StrategyRunningMonitor):
    """策略运行监控控件"""

    def __init__(self, eventEngine=None):
        super(StrategyRunningMonitor, self).__init__()
        self.strategyDict = {}
        self.runningDict = {}

        self.eventEngine = eventEngine

        self.setupUi(self)

    def setEventEngine(self, eventEngine):
        self.eventEngine = eventEngine

    def addStrategy(self, strategyName, strategyclass):
        self.strategyDict[strategyName] = strategyclass

    def setupMenu(self, actionNames, actionEvents):
        """初始化右键菜单"""
        self.menu = QtWidgets.QMenu(self)

        saveAction = QtWidgets.QAction('保存内容', self)
        saveAction.triggered.connect(self.saveToCsv)
        self.menu.addAction(saveAction)

    def registerEvent(self):
        """注册事件监听"""
        # self.signal.connect(self.updateMonitor)
        # self.eventEngine.register(EVENT_CTA_STRATEGY + self.name, self.signal.emit)


########################################################################
class CtaValueMonitor(QtWidgets.QTableWidget):
    """参数监控"""

    def __init__(self, parent=None):
        """Constructor"""
        super(CtaValueMonitor, self).__init__(parent)

        self.keyCellDict = {}
        self.data = None
        self.inited = False

        self.initUi()

    def initUi(self):
        """初始化界面"""
        self.setRowCount(1)
        self.verticalHeader().setVisible(False)
        self.setEditTriggers(self.NoEditTriggers)

        self.setMaximumHeight(self.sizeHint().height())

    def updateData(self, data):
        """更新数据"""
        if not self.inited:
            self.setColumnCount(len(data))
            self.setHorizontalHeaderLabels(list(data.keys()))

            col = 0
            for k, v in list(data.items()):
                cell = QtWidgets.QTableWidgetItem(str(v))
                self.keyCellDict[k] = cell
                self.setItem(0, col, cell)
                col += 1

            self.inited = True
        else:
            for k, v in list(data.items()):
                cell = self.keyCellDict[k]
                cell.setText(str(v))


class TreeManager(QtWidgets.QTreeView):
    """树类数据管理"""

    def __init__(self, parent=None):
        """Constructor"""
        super(TreeManager, self).__init__(parent)

        self.keyCellDict = {}
        self.data = None
        self.inited = False

        self.initUi()

    def initUi(self):
        """初始化界面"""
        self.setRowCount(1)
        self.verticalHeader().setVisible(False)
        self.setEditTriggers(self.NoEditTriggers)

        self.setMaximumHeight(self.sizeHint().height())

    def updateData(self, data):
        """更新数据"""
        if not self.inited:
            self.setColumnCount(len(data))
            self.setHorizontalHeaderLabels(list(data.keys()))

            col = 0
            for k, v in list(data.items()):
                cell = QtWidgets.QTableWidgetItem(str(v))
                self.keyCellDict[k] = cell
                self.setItem(0, col, cell)
                col += 1

            self.inited = True
        else:
            for k, v in list(data.items()):
                cell = self.keyCellDict[k]
                cell.setText(str(v))


########################################################################
class CtaParamsManager(QtWidgets.QGroupBox):
    """策略管理组件"""
    signal = QtCore.pyqtSignal(type(Event()))

    def __init__(self, strategyEngine, eventEngine, name, parent=None):
        """Constructor"""
        super(CtaParamsManager, self).__init__(parent)

        self.strategyEngine = strategyEngine
        self.eventEngine = eventEngine
        self.name = name

        self.initUi()
        self.updateMonitor()
        self.registerEvent()

    def initUi(self):
        # print("""初始化策略参数管理界面""")
        self.setTitle(self.name)

        self.paramMonitor = CtaValueMonitor(self)
        self.varMonitor = CtaValueMonitor(self)

        maxHeight = 60
        self.paramMonitor.setMaximumHeight(maxHeight)
        self.varMonitor.setMaximumHeight(maxHeight)

        buttonSelectStrategy = QtWidgets.QPushButton('选择策略')
        buttonSetParams = QtWidgets.QPushButton('参数设置')
        buttonOptimiseParams = QtWidgets.QPushButton('参数优化')
        buttonSelectStrategy.clicked.connect(self.selectStrategy)
        buttonSetParams.clicked.connect(self.setParams)
        buttonOptimiseParams.clicked.connect(self.optimiseParams)

        hbox1 = QtWidgets.QHBoxLayout()
        hbox1.addWidget(buttonSelectStrategy)
        hbox1.addWidget(buttonSetParams)
        hbox1.addWidget(buttonOptimiseParams)
        hbox1.addStretch()

        hbox2 = QtWidgets.QHBoxLayout()
        hbox2.addWidget(self.paramMonitor)

        hbox3 = QtWidgets.QHBoxLayout()
        hbox3.addWidget(self.varMonitor)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addLayout(hbox1)
        vbox.addLayout(hbox2)
        vbox.addLayout(hbox3)

        self.setLayout(vbox)

    def updateMonitor(self, event=None):
        """显示策略最新状态"""

        # print('updateMonitor')
        paramDict = self.strategyEngine.get_strategy_params(self.name)

        if paramDict:
            self.paramMonitor.updateData(paramDict)

        varDict = self.strategyEngine.getStrategyVar(self.name)
        if varDict:
            self.varMonitor.updateData(varDict)
            # print('updateMonitor is ok!')

    def registerEvent(self):
        """注册事件监听"""
        self.signal.connect(self.updateMonitor)
        self.eventEngine.register(EVENT_CTA_STRATEGY + self.name, self.signal.emit)

    def selectStrategy(self):
        """初始化策略"""
        self.strategyEngine.init_strategy(self.name)

    def setParams(self):
        """启动策略"""
        self.strategyEngine.start_strategy(self.name)

    def optimiseParams(self):
        """停止策略"""
        self.strategyEngine.stop_strategy(self.name)


class CtaStrategyManager(QtWidgets.QGroupBox):
    """策略管理组件"""
    signal = QtCore.pyqtSignal(type(Event()))

    def __init__(self, strategyEngine, eventEngine, name, parent=None):
        """Constructor"""
        super(CtaStrategyManager, self).__init__(parent)

        self.strategyEngine = strategyEngine
        self.eventEngine = eventEngine
        self.name = name

        self.initUi()
        # self.updateMonitor()
        # self.registerEvent()

    def initUi(self):
        # print("""初始化策略管理界面""")
        self.setTitle(self.name)

        self.paramMonitor = CtaValueMonitor(self)
        self.varMonitor = CtaValueMonitor(self)

        maxHeight = 60
        self.paramMonitor.setMaximumHeight(maxHeight)
        self.varMonitor.setMaximumHeight(maxHeight)

        buttonInit = QtWidgets.QPushButton('初始化')
        buttonStart = QtWidgets.QPushButton('启动')
        buttonStop = QtWidgets.QPushButton('停止')
        buttonInit.clicked.connect(self.init)
        buttonStart.clicked.connect(self.start)
        buttonStop.clicked.connect(self.stop)

        hbox1 = QtWidgets.QHBoxLayout()
        hbox1.addWidget(buttonInit)
        hbox1.addWidget(buttonStart)
        hbox1.addWidget(buttonStop)
        hbox1.addStretch()

        hbox2 = QtWidgets.QHBoxLayout()
        hbox2.addWidget(self.paramMonitor)

        hbox3 = QtWidgets.QHBoxLayout()
        hbox3.addWidget(self.varMonitor)

        vbox = QtWidgets.QVBoxLayout()
        vbox.addLayout(hbox1)
        vbox.addLayout(hbox2)
        vbox.addLayout(hbox3)

        self.setLayout(vbox)

    def updateMonitor(self, event=None):
        """显示策略最新状态"""

        # print('updateMonitor')
        paramDict = self.strategyEngine.get_strategy_params(self.name)

        if paramDict:
            self.paramMonitor.updateData(paramDict)

        varDict = self.strategyEngine.getStrategyVar(self.name)
        if varDict:
            self.varMonitor.updateData(varDict)
            # print('updateMonitor is ok!')

    def registerEvent(self):
        """注册事件监听"""
        self.signal.connect(self.updateMonitor)
        self.eventEngine.register(EVENT_CTA_STRATEGY + self.name, self.signal.emit)

    def init(self):
        """初始化策略"""
        self.strategyEngine.init_strategy(self.name)

    def start(self):
        """启动策略"""
        self.strategyEngine.start_strategy(self.name)

    def stop(self):
        """停止策略"""
        self.strategyEngine.stop_strategy(self.name)


########################################################################
class StrategyEngineManager(QtWidgets.QWidget):
    """CTA引擎管理组件"""
    signal = QtCore.pyqtSignal(type(Event()))

    def __init__(self, strategyEngine=None, eventEngine=None, parent=None):
        """Constructor"""
        super(StrategyEngineManager, self).__init__(parent)
        # self.account_engine=strategyEngine.account_engine
        # self.quoteEngine=self.account_engine.quoteEngine

        self.strategyEngine = strategyEngine
        self.quoteEngine = eventEngine
        self.eventEngine = eventEngine

        self.strategyLoaded = False

        self.initUi()
        # self.registerEvent()

        # 记录日志
        # self.strategyEngine.req_log('CTA引擎启动成功')
        print('CTA引擎启动成功')

    def initUi(self):
        """初始化界面"""
        self.setWindowTitle('CTA策略')

        # 按钮
        loadButton = QtWidgets.QPushButton('加载策略')
        initAllButton = QtWidgets.QPushButton('全部初始化')
        startAllButton = QtWidgets.QPushButton('全部启动')
        stopAllButton = QtWidgets.QPushButton('全部停止')
        optimiseButton = QtWidgets.QPushButton('策略参数优化')

        loadButton.clicked.connect(self.load)
        initAllButton.clicked.connect(self.initAll)
        startAllButton.clicked.connect(self.startAll)
        stopAllButton.clicked.connect(self.stopAll)
        optimiseButton.clicked.connect(self.optimise)
        # 滚动区域，放置所有的CtaStrategyManager
        self.scrollArea = QtWidgets.QScrollArea()
        self.scrollArea.setWidgetResizable(True)

        self.runningMonitor = StrategyRunningMonitor()

        # CTA组件的日志监控
        self.ctaLogMonitor = QtWidgets.QTextEdit()
        self.ctaLogMonitor.setReadOnly(True)
        self.ctaLogMonitor.setMaximumHeight(200)

        # 设置布局
        hbox2 = QtWidgets.QHBoxLayout()
        hbox2.addWidget(loadButton)
        hbox2.addWidget(initAllButton)
        hbox2.addWidget(startAllButton)
        hbox2.addWidget(stopAllButton)
        hbox2.addStretch()

        vbox = QtWidgets.QVBoxLayout()
        vbox.addLayout(hbox2)
        vbox.addWidget(self.scrollArea)
        vbox.addWidget(self.runningMonitor)
        vbox.addWidget(self.ctaLogMonitor)
        self.setLayout(vbox)

    def initStrategyManager(self):
        """初始化策略管理组件界面"""
        w = QtWidgets.QWidget()
        vbox = QtWidgets.QVBoxLayout()

        for name in list(self.strategyEngine.strategyDict.keys()):
            # print(name)
            strategyManager = CtaStrategyManager(self.strategyEngine, self.eventEngine, name)
            # print(name)
            vbox.addWidget(strategyManager)

        vbox.addStretch()

        w.setLayout(vbox)
        self.scrollArea.setWidget(w)

    def initAll(self):
        """全部初始化"""
        for name in list(self.strategyEngine.strategyDict.keys()):
            self.strategyEngine.init_strategy(name)

    def startAll(self):
        """全部启动"""
        for name in list(self.strategyEngine.strategyDict.keys()):
            self.strategyEngine.start_strategy(name)

    def stopAll(self):
        """全部停止"""
        for name in list(self.strategyEngine.strategyDict.keys()):
            self.strategyEngine.stop_strategy(name)
            self.strategyLoaded = False

    def load(self):
        """加载策略"""
        if not self.strategyLoaded:
            # print('ctaEngine.loadSetting')
            self.strategyEngine.load_settings()
            # print('initStrategyManager')
            self.initStrategyManager()
            self.strategyLoaded = True
            self.strategyEngine.req_log('策略加载成功')

    def optimise(self):
        self.strategyLoaded = True

    def updateCtaLog(self, event):
        """更新CTA相关日志"""
        log = event.dict_['data']
        content = '\t'.join([log.logTime, log.logContent])
        self.ctaLogMonitor.append(content)

    def registerEvent(self):
        """注册事件监听"""
        self.signal.connect(self.updateCtaLog)
        self.eventEngine.register(EVENT_CTA_LOG, self.signal.emit)

    def closeEvent(self, event):
        for name in list(self.strategyEngine.strategyDict.keys()):
            self.strategyEngine.stop_strategy(name)
        self.strategyLoaded = False

        event.accept()


class StrategyInstrumentManager(object):
    """
    策略标的管理类，将策略类与交易标的结合，生成具体策略实例
    """

    def __init__(self, dbType=DBTYPE_MONGODB, dbClient=None):
        # 数据保存及获取相关配置
        self._dbType = dbType
        if dbClient is None:
            self._dbClient = DbHelper(self._dbType)
        else:
            self._dbClient = dbClient

        self.instrumentDict = {}  # 标的字典
        self.strategyDict = {}  # 策略字典

    def addStrategy(self, strategyName, strategyClass):
        """
        向策略字典中添加项目
        :param strategyName: 策略名称，构成方式：策略类名称.标的代码.周期
        :param strategyClass: 具体策略实例
        :return:
        """
        self.strategyDict[strategyName] = strategyClass

    def addInstrument(self, instrumentID, instrument):
        """
        向标的字典中添加项目
        :param instrumentID: 标的ID，构成方式：交易所ID.标的ID
        :param instrument:
        :return:
        """
        self.instrumentDict[instrumentID] = instrument


class StrategyTradeManager(object):
    """
    策略交易管理类，将配置好的策略与交易账户关联
    """

    def __init__(self, dbType=DbType.DBTYPE_MONGODB.value, dbClient=None):
        # 数据保存及获取相关配置
        self._dbType = dbType
        if dbClient is None:
            self._dbClient = DbHelper(self._dbType)
        else:
            self._dbClient = dbClient

        self.accountDict = {}  # 账户字典
        self.strategyDict = {}  # 策略字典
        self.instrumentDict = {}  # 标的字典

    def addStrategy(self, strategyName, strategyClass):
        """
        向策略字典中添加项目
        :param strategyName: 策略名称，构成方式：策略类名称.标的代码.周期
        :param strategyClass: 具体策略实例
        :return:
        """
        self.strategyDict[strategyName] = strategyClass

    def addInstrument(self, instrumentID, instrument):
        """
        向标的字典中添加项目
        :param instrumentID: 标的ID，构成方式：交易所ID.标的ID
        :param instrument:
        :return:
        """
        self.instrumentDict[instrumentID] = instrument

    def addAccount(self, accountID, account):
        """
         向账户字典中添加项目
        :param accountID: 账户ID，构成：brokerID.investorID
        :param account:
        :return:
        """
        self.accountDict[accountID] = account


if __name__ == '__main__':
    from event_engine.quote_engine import QuoteEngine
    import sys
    from dbhelper.box_db import DbHelper, DBTYPE_MONGODB
    from base.data_engine import DataEngine as DrEngine

    # fp = loadSqlitSettings()
    # print(fp)
    # 初始化Qt应用对象
    app = QtWidgets.QApplication(sys.argv)
    # 设置数据保存方式及相应的客户端
    dbType = DBTYPE_MONGODB
    dbClient = DbHelper(dbType)

    isTest = False
    # 行情引擎及其事件
    quoteEngine = QuoteEngine()
    quoteEventEngine = quoteEngine
    time.sleep(1)
    # 数据引擎
    drEngine = DrEngine(quote_event_engine=quoteEngine,  db_client=dbClient)

    # 策略引擎 -- 实盘交易用
    # account_engine = StrategyEngine(quoteEngine)
    # 策略引擎 --  实盘测试用
    mainEngine = StrategyTestEngine(drEngine)

    mainWindow = StrategyEngineManager()
    mainWindow.showMaximized()

    sys.exit(app.exec_())
